package com.stp.dtl645;

import com.stp.util.HexConverter;

import java.math.BigDecimal;
import java.util.*;

public class Dlt6452007Hex {
    public static String create_DLT6452007_verificationCode(List<String> split) {
        int i = 0;
        for (String s: split){
            i += Integer.parseInt(s,16) % 256;
        }
        return Integer.toHexString(i % 256).toUpperCase(Locale.ROOT);
    }

    public static void main(String[] args) {

        String addressCode = "220716131252";

        String dataString = "/v7+/mgmB1UgESNokQgzMzQzMzMzM9gW";
        //String hex = "fefefefe682607552011236891083333343333333333d816";

        //读取正向有功电脑数据块模拟错误(因为电表没有数据)
        //String dataString = "/v7+/mgmB1UgESNo0QE1rRY=";
        //String hex = "fefefefe6826075520112368d10135ad16";

        //读取正向有功电脑数据块模拟
        //String hexStr = "FEFEFEFE6852121316072268911833323433644A3433834B333388583333BB7733336B5B33334E16";

        byte[] dataBytes = Base64.getDecoder().decode(dataString);
        //String hexStr = HexUtil.encodeHexStr(dataBytes);

        String hexStr = "FE686272501509216891083333343389934C333416";



        hexStr = removePreposeFrame(hexStr);
        String commandRCVD = HexConverter.fillBlank(hexStr);
        String[] commands = Objects.requireNonNull(commandRCVD).trim().split(" ");
        if (commands.length < Dlt645Frame.MIN_FRAME_LEN ||
                !commands[0].equals(Dlt645Frame.FRAME_STARTER) || !commands[commands.length - 1].equals(Dlt645Frame.FRAME_END)) {
            String deviceId = getAmmeterIdFromResponseFrame(hexStr);
            String errorMsg = "返回数据出错";
            if(commandRCVD.contains("D1") || commandRCVD.contains("d1")){
                errorMsg = "异常";
            }
        }else {
            //解析数据标识
            List<String> list2 = new ArrayList<>();
            for (int i = 0; i < 4; i++) {
                list2.add(Integer.toHexString(Integer.parseInt(commands[commands.length - 3 - i - (Integer.parseInt(commands[9], 16) - 4)], 16) - 51));
            }
            //4字节的数据标识
            String[] DTID = list2.toArray(new String[list2.size()]);
            StringBuilder dataIdentification = new StringBuilder();
            for (int i = 0; i < DTID.length; i++) {
                if (DTID[i].length() == 1) {
                    DTID[i] = String.format("%02d", Integer.parseInt(DTID[i]));
                } else if (DTID[i].length() == 8) {
                    DTID[i] = "FF";
                }
                dataIdentification.append(DTID[i]);
            }
            if (commands.length > Dlt645Frame.MIN_FRAME_LEN) {
                List<String> list3 = new ArrayList<>();
                for (int i = 0; i < Integer.parseInt(commands[9], 16) - 4; i++) {
                    list3.add(commands[commands.length - 3 - i]);
                }

                if("00010000".equals(dataIdentification.toString())){
                    //正向有功总电能
                    String[] data = list3.toArray(new String[list3.size()]);
                    long num = Long.parseLong((dataFormat(data)).toString());
                    BigDecimal bigDecimal = new BigDecimal(num);
                    double energy = Double.parseDouble(String.valueOf(bigDecimal.multiply(new BigDecimal("0.01"))));
                    System.out.println(energy);
                }else if("0001FF00".equals(dataIdentification.toString()) || "0001ff00".equals(dataIdentification.toString())){
                    //正向有功总电能代码块
                    String[] array = list3.toArray(new String[list3.size()]);
                    //正向有功总电能
                    long powerConsumptionNum = Long.parseLong((dataFormat(Arrays.copyOfRange(array, 16, 20))).toString());
                    double power_consumption = Double.parseDouble(String.valueOf(new BigDecimal(powerConsumptionNum).multiply(new BigDecimal("0.01"))));
                    System.out.println("正向有功总电能  = "+ power_consumption);
                    //尖
                    long topNum = Long.parseLong((dataFormat(Arrays.copyOfRange(array, 12, 16))).toString());
                    double top = Double.parseDouble(String.valueOf(new BigDecimal(topNum).multiply(new BigDecimal("0.01"))));
                    System.out.println("尖  = "+ top);
                    //峰
                    long peakNum = Long.parseLong((dataFormat(Arrays.copyOfRange(array, 8, 12))).toString());
                    double peak = Double.parseDouble(String.valueOf(new BigDecimal(peakNum).multiply(new BigDecimal("0.01"))));
                    System.out.println("峰  = "+ peak);
                    //平
                    long flatNum = Long.parseLong((dataFormat(Arrays.copyOfRange(array, 4, 8))).toString());
                    double flat = Double.parseDouble(String.valueOf(new BigDecimal(flatNum).multiply(new BigDecimal("0.01"))));
                    System.out.println("平  = "+ flat);
                    //谷
                    long valleyNum = Long.parseLong((dataFormat(Arrays.copyOfRange(array, 0, 4))).toString());
                    double valley = Double.parseDouble(String.valueOf(new BigDecimal(valleyNum).multiply(new BigDecimal("0.01"))));
                    System.out.println("谷  = "+ valley);
                }
            }
        }

        System.out.println(getAmmeterIdFromResponseFrame(hexStr));
        send("");
    }

    /**
     * 高位在后，低位在前 ["33", "34", "4A", "64"]
     * 33 = 00110011
     * 34 = 00110100
     * 4A = 01001010
     * 64 = 01100100
     * @param data
     * @return
     */
    private static StringBuffer dataFormat(String[] data) {
        StringBuffer sbr = new StringBuffer();
        for (String datum : data) {
            String data1 = String.valueOf(Integer.parseInt(datum.substring(0, 1), 16) - 3);
            String data2 = String.valueOf(Integer.parseInt(datum.substring(1), 16) - 3);
            sbr.append(data1);
            sbr.append(data2);
        }
        return sbr;
    }

    /**
     * 从电表响应的16进制帧数据中解析出电表的表号
     * <pre>
     * 电表正常回应数据格式：
     * 68[370300928139]68910833333433373333338C16"
     *   |<--地址码-->|
     * <pre/>
     *
     * @param hexString 16进制字符串
     * @return 电表的表号
     */
    public static String getAmmeterIdFromResponseFrame(String hexString) {
        if (Objects.isNull(hexString)) {
            throw new NullPointerException("Illegal frame , cannot be parsed!");
        }
        String newHexString = hexString;
        //判断是否有返回 前置帧 FEFEFE
        if(newHexString.contains("FEFEFEFE") || newHexString.contains("fefefefe")){
            newHexString = newHexString.replaceAll("FEFEFEFE","");
            newHexString = newHexString.replaceAll("fefefefe","");
        }
        StringBuilder eleMeterId = new StringBuilder();
        String responseFrame = HexConverter.fillBlank(newHexString);
        String[] messageArray = Objects.requireNonNull(responseFrame).split(" ");
        Stack<String> stack = new Stack<>();
        for (int i = 1; i <= Dlt645Frame.ADDRESS_FIELD_LEN; i++) {
            stack.push(messageArray[i]);
        }
        while (!stack.isEmpty()) {
            String byteStr = stack.pop();
            eleMeterId.append(byteStr);
        }
        return eleMeterId.toString();
    }

    /**
     * 删除前置帧
     * @param hexString
     * @return
     */
    public static String removePreposeFrame(String hexString){
        while (Objects.equals("FE",hexString.substring(0,2))){
            hexString = hexString.replaceFirst("FE","");
        }
        while (Objects.equals("fe",hexString.substring(0,2))){
            hexString = hexString.replaceFirst("fe","");
        }
        return hexString;
    }

    /**
     * 输入电表的编号，得到数据帧中的地址域
     *
     * @param meterNumber 电表编号
     * @return
     */
    public static String getAddressFiled(String meterNumber) {
        if (Objects.isNull(meterNumber) || meterNumber.length() == 0) {
            throw new IllegalArgumentException("meter number must not be empty");
        }
        char[] meterNum = meterNumber.toCharArray();
        String[] addressField = new String[6];
        Arrays.fill(addressField, "00");
        int indexOfArray = 0;
        for (int i = meterNum.length - 1; i >= 0 && indexOfArray < addressField.length; i--) {
            addressField[indexOfArray++] = String.valueOf(meterNum[i - 1]).concat(String.valueOf(meterNum[i]));
            i -= 1;
        }
        StringBuilder sb = new StringBuilder();
        for (String str : addressField) {
            sb.append(str).append(" ");
        }
        return sb.toString();
    }

    private static void send(String deviceId){
        //String addressCode = "231120550726";
        String addressCode = "210915507262";
        List<String> list1 = strSplitList(addressCode);
        Collections.reverse(list1);//位置互换
        addressCode = "";
        for (String s : list1){
            addressCode = addressCode.concat(s);
        }
        //需要补齐12位
        while ((addressCode.length() % 2 != 0) || addressCode.length() < 12){
            addressCode = addressCode.concat("0");
        }
        //指令
        String instruct = "68"+addressCode+"68110433333433";
        //String instruct = "68"+addressCode+"68110433323433";
        //分隔 两个字符一组
        List<String> splitArray = strSplitList(instruct);
        String verificationCode = create_DLT6452007_verificationCode(splitArray);
        instruct = "FEFEFEFE" + instruct + verificationCode + "16";
        System.out.println(instruct);
    }


    private static List<String> strSplitList(String str){
        List<String> splitArray = new ArrayList<>();
        for (int i = 0;i < (str.length() + 1) / 2;i++){
            int start = i * 2;
            int end = Math.min(start+2,str.length());
            splitArray.add(str.substring(start,end));
        }
        return splitArray;
    }

}
